package org.zsk.cfl.cmd.impl;

import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.impl.dynamic.BaseDynamicSubProcessInjectUtil;
import org.flowable.engine.impl.dynamic.DynamicEmbeddedSubProcessBuilder;
import org.flowable.engine.impl.persistence.entity.DeploymentEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.impl.persistence.entity.ResourceEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.ProcessDefinition;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *     动态子流程插入工具
 * </p>
 *
 * @author zsk
 * @date 2020/11/4 下午9:43
 */
public class DynamicSubProcessInjectUtil  extends BaseDynamicSubProcessInjectUtil {

    public static void injectSerialSubProcess(Process process, BpmnModel bpmnModel, DynamicEmbeddedSubProcessBuilder dynamicEmbeddedSubProcessBuilder,
                                                ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity, CommandContext commandContext, String activityId) {

        FlowNode chosenFlow=(FlowNode)process.getFlowElement(activityId);
        List<SequenceFlow> chosenOutgoings=chosenFlow.getOutgoingFlows();
        SequenceFlow chosenSeqFlow=chosenOutgoings.get(0);
        FlowNode chosenNextFlow=(FlowNode)process.getFlowElement(chosenSeqFlow.getTargetRef());
        process.removeFlowElement(chosenSeqFlow.getId());

        GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(chosenFlow.getId());

        SubProcess subProcess = new SubProcess();
        if (dynamicEmbeddedSubProcessBuilder.getId() != null) {
            subProcess.setId(dynamicEmbeddedSubProcessBuilder.getId());
        } else {
            subProcess.setId(dynamicEmbeddedSubProcessBuilder.nextSubProcessId(process.getFlowElementMap()));
        }
        dynamicEmbeddedSubProcessBuilder.setDynamicSubProcessId(subProcess.getId());

        ProcessDefinition subProcessDefinition = ProcessDefinitionUtil.getProcessDefinition(dynamicEmbeddedSubProcessBuilder.getProcessDefinitionId());
        ResourceEntity subProcessBpmnResource = CommandContextUtil.getResourceEntityManager(commandContext)
                .findResourceByDeploymentIdAndResourceName(subProcessDefinition.getDeploymentId(), subProcessDefinition.getResourceName());
        BpmnModel bpmnModelSubProcess = new BpmnXMLConverter().convertToBpmnModel(new BytesStreamSource(subProcessBpmnResource.getBytes()), false, false);
        for (FlowElement flowElement : bpmnModelSubProcess.getMainProcess().getFlowElements()) {
            subProcess.addFlowElement(flowElement);
        }

        processFlowElements(commandContext, process, bpmnModel, originalProcessDefinitionEntity, newDeploymentEntity);

        Map<String, FlowElement> generatedIds = new HashMap<>();
        processSubProcessFlowElements(commandContext, subProcess.getId(), process, bpmnModel, subProcess, bpmnModelSubProcess,
                subProcessDefinition, newDeploymentEntity, generatedIds, (elementGraphicInfo != null));

        for (String originalFlowElementId : generatedIds.keySet()) {
            FlowElement duplicateFlowElement = generatedIds.get(originalFlowElementId);
            duplicateFlowElement.getParentContainer().removeFlowElementFromMap(originalFlowElementId);
            duplicateFlowElement.getParentContainer().addFlowElementToMap(duplicateFlowElement);
        }

        process.addFlowElement(subProcess);

        SequenceFlow flowToSubProcess = new SequenceFlow(chosenFlow.getId(), subProcess.getId());
        flowToSubProcess.setId(dynamicEmbeddedSubProcessBuilder.nextFlowId(process.getFlowElementMap()));
        process.addFlowElement(flowToSubProcess);

        SequenceFlow flowFromSubProcess = new SequenceFlow(subProcess.getId(), chosenNextFlow.getId());
        flowFromSubProcess.setId(dynamicEmbeddedSubProcessBuilder.nextFlowId(process.getFlowElementMap()));
        process.addFlowElement(flowFromSubProcess);

        new BpmnAutoLayout(bpmnModel).execute();
//        if (elementGraphicInfo != null) {
//            double yDiff = 0;
//            double xDiff = 80;
//            if (elementGraphicInfo.getY() < 173) {
//                yDiff = 173 - elementGraphicInfo.getY();
//                elementGraphicInfo.setY(173);
//            }
//
//            Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
//            for (String locationId : locationMap.keySet()) {
//                if (chosenFlow.getId().equals(locationId)) {
//                    continue;
//                }
//
//                GraphicInfo locationGraphicInfo = locationMap.get(locationId);
//                locationGraphicInfo.setX(locationGraphicInfo.getX() + xDiff);
//                locationGraphicInfo.setY(locationGraphicInfo.getY() + yDiff);
//            }
//
//            Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel.getFlowLocationMap();
//            for (String flowId : flowLocationMap.keySet()) {
//                if (flowToSubProcess.getId().equals(flowId)) {
//                    continue;
//                }
//
//                List<GraphicInfo> flowGraphicInfoList = flowLocationMap.get(flowId);
//                for (GraphicInfo flowGraphicInfo : flowGraphicInfoList) {
//                    flowGraphicInfo.setX(flowGraphicInfo.getX() + xDiff);
//                    flowGraphicInfo.setY(flowGraphicInfo.getY() + yDiff);
//                }
//            }
//
//            GraphicInfo forkGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() - 5, 40, 40);
//            bpmnModel.addGraphicInfo(chosenFlow.getId(), forkGraphicInfo);
//
//            bpmnModel.addFlowGraphicInfoList(flowToSubProcess.getId(), createWayPoints(elementGraphicInfo.getX() + 30, elementGraphicInfo.getY() + 15,
//                    elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() + 15));
//
//            GraphicInfo newSubProcessGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 163, 80, 100);
//            newSubProcessGraphicInfo.setExpanded(false);
//            bpmnModel.addGraphicInfo(subProcess.getId(), newSubProcessGraphicInfo);
//
//            bpmnModel.addFlowGraphicInfoList(flowToSubProcess.getId(), createWayPoints(elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 5,
//                    elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 123, elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 123));
//
//            GraphicInfo endGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 335, elementGraphicInfo.getY() - 137, 28, 28);
//            bpmnModel.addGraphicInfo(chosenNextFlow.getId(), endGraphicInfo);
//
//            bpmnModel.addFlowGraphicInfoList(flowFromSubProcess.getId(), createWayPoints(elementGraphicInfo.getX() + 285, elementGraphicInfo.getY() - 123,
//                    elementGraphicInfo.getX() + 335, elementGraphicInfo.getY() - 123));
//        }
    }

}
